package org.dromara.mall.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.mall.domain.vo.TerMallProductVo;
import org.dromara.mall.service.ITerFullSyncService;
import org.dromara.mall.service.ITerMallProductService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
@RequiredArgsConstructor
@Service
public class TerFullSyncServiceImpl implements ITerFullSyncService {
    private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class);
    private final ITerMallProductService terMallProductService;
    private static final String INVENTORY_KEY = "mall:inventory:{productId}";
    private final RedisTemplate<String, String> redisTemplate;
    @Override
    public void scheduleFullSync() {
        RLock lock = CLIENT.getLock("inventory:full-sync:lock");
        try {
            if (lock.tryLock(10, 60, TimeUnit.SECONDS)) {
                syncAllInventory();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }

    @Async
    public void syncAllInventory() {
        List<TerMallProductVo> inventoryList = terMallProductService.queryList(null);
        if (CollectionUtils.isEmpty(inventoryList)) return;

        inventoryList.forEach(av -> {
            String key = buildInventoryKey(av.getId());
            redisTemplate.opsForValue().set(key, String.valueOf(av.getStock()));
        });
    }

    public String buildInventoryKey(Long productId) {
        return INVENTORY_KEY
            .replace("{productId}", productId.toString());
    }

    @Override
    // 原子化库存扣减
    public boolean deductInventory(Long prouductId, int quantity) {
        String key = buildInventoryKey(prouductId);
        RLock lock = CLIENT.getLock(key + ":rollback_lock"); // 回滚专用锁
        try {
            Long remaining = redisTemplate.opsForValue().decrement(key, quantity);

            if (remaining != null && remaining >= 0) {
                return true;
            } else {
                // 加锁保证回滚原子性
                if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
                    redisTemplate.opsForValue().increment(key, quantity);
                }
                return false;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    @Override
    public boolean judgeInventory(Long prouductId, Integer quantity) {
        String key = buildInventoryKey(prouductId);
        String quantityStr= redisTemplate.opsForValue().get(key);
        if (StringUtils.isBlank(quantityStr)) {
            return false;
        }
        return  Integer.valueOf(quantityStr) >= quantity;
    }
}
